﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using System.Xml;
using Timer=System.Threading.Timer;

namespace SearchRS
{
    public enum ResultState
    {
        Unverified,
        Verified,
        VerifiedAndEmpty
    }

    public class ResultDetails
    {
        public string Title { get; set; }
        public List<string> Links { get; set; }
        public string Password { get; set; }
        public ResultState State { get; set; }
        public string Url { get; set; }
        public Timer StateTimer { get; set; }
        public ManualResetEvent WaitEvent { get; set; }
        public string SubsLinks { get; set; }

        public ResultDetails(string title, List<string> links, ResultState state, string password, string url, string subsLink)
        {
            Title = title;
            Links = links;
            State = state;
            Password = password;
            Url = url;
            SubsLinks = subsLink;
        }

        public override string ToString()
        {
            string title = Title;
            if (!string.IsNullOrEmpty(Password))
                title += " (password: " + Password + ")";
            return title;
        }

        public void DumpToXml(string filename)
        {
            if (File.Exists(filename))
            {
                File.Delete(filename);
            }

            XmlWriterSettings x = new XmlWriterSettings();
            x.Encoding = Encoding.ASCII;
            using (XmlWriter writer = XmlWriter.Create(filename, x))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("ResultDetails");

                writer.WriteElementString("Title", Title);
                writer.WriteStartElement("Links");
                if (Links != null)
                {
                    foreach (string link in Links)
                    {
                        writer.WriteElementString("Link", link);
                    }
                }
                writer.WriteEndElement();

                writer.WriteElementString("State", Enum.GetName(typeof (ResultState), State));
                writer.WriteElementString("Password", Password);
                writer.WriteElementString("Url", Url);
                writer.WriteElementString("SubsLinks", SubsLinks);

                writer.WriteEndElement();
                writer.WriteEndDocument();
            }
        }
    }

    public class SearchResults
    {
        private GUI m_gui;
        private Dictionary<int, ResultDetails> results;
        private OperationMode m_operationMode;
        private int m_apiCounter;

        public SearchResults(GUI gui, OperationMode operationMode)
        {
            m_gui = gui;
            m_apiCounter = 0;
            m_operationMode = operationMode;
            results = new Dictionary<int, ResultDetails>();
        }

        public int AddResult(string title, string url, List<string> links, string subsLink, string password, ResultState state)
        {
            int id;

            ResultDetails details = new ResultDetails(title, links, state, password, url, subsLink);

            switch (m_operationMode)
            {
                case OperationMode.GUI:
                    {
                        id = m_gui.AddResult(details);

                        lock (results)
                        {
                            results.Add(id, details);
                        }
                    }
                    break;
                case OperationMode.JDownloadePlugin:
                    {
                        m_apiCounter++;
                        id = m_apiCounter;
                        lock (results)
                        {
                            results.Add(m_apiCounter, details);
                        }

                        string tempFilename = Path.Combine(Path.GetTempPath(), "A" + id);
                        details.DumpToXml(tempFilename);
                        Console.WriteLine("{0},{1},{2}",
                            id,
                            "A",
                            tempFilename);
                    }
                    break;
                case OperationMode.CLI:
                default:
                    throw new ArgumentException("Invalid operation mode " + m_operationMode);
            }

            return id;
        }

        public void Clear()
        {
            lock (results)
            {
                results.Clear();
            }
        }

        public ResultState GetResultState(int index)
        {
            return results[index].State;
        }

        public List<string> GetLinks(int index)
        {
            if (results[index].State == ResultState.Unverified)
            {
                results[index].WaitEvent = new ManualResetEvent(false);
                results[index].StateTimer = new Timer(timercallback, index, 1000, 1000);

                bool ret = results[index].WaitEvent.WaitOne(60000, false);
                if (ret)
                {
                    return results[index].Links;
                }
            }

            return results[index].Links;
        }

        public string GetSubsLink(int index)
        {
            return results[index].SubsLinks;
        }

        private void timercallback(object state)
        {
            int index = (int) state;
            if (results[index].State == ResultState.Verified)
            {
                results[index].StateTimer.Dispose();
                results[index].WaitEvent.Set();
            }
        }

        public void UpdateResult(int id, List<string> links, string subsLink, string password, ResultState state)
        {
            lock (results)
            {
                results[id].Links = links;
                results[id].State = state;
                results[id].Password = password;
                results[id].SubsLinks = subsLink;
            }
            
            ResultDetails details = new ResultDetails(results[id].Title, links, state, password, results[id].Url, subsLink);

            switch (m_operationMode)
            {
                case OperationMode.GUI:
                    {
                        m_gui.UpdateResult(id, details);
                    }
                    break;
                case OperationMode.JDownloadePlugin:
                    {
                        string tempFilename = Path.Combine(Path.GetTempPath(), "U" + id);
                        details.DumpToXml(tempFilename); 
                        Console.WriteLine("{0},{1},{2}",
                            id,
                            "U",
                            tempFilename);
                    }
                    break;
                case OperationMode.CLI:
                default:
                    throw new ArgumentException("Invalid operation mode " + m_operationMode);
            }
        }

        public string GetPassword(int index)
        {
            return results[index].Password;
        }

    }
}